vlwkaos' digital garden

JavaScript - Scope

Declaration

  • Scope: 선언한 것을 찾을 수 있는 범위. 정적인 속성이다.
  • Activation: 선언한 것을 언제 실제로 사용할 수 있는지. 동적인 속성이다.
    • Scope 내에서 바로 접근 가능한 것들이 있고, 실행 후 선언부(실제 선언하는 코드)까지 도달해야 접근 가능한 것들이 있다.
ScopeActivationDuplicatesGlobal prop.
constBlockdecl.(TDZ)XX
letBlockdecl.(TDZ)XX
functionBlock*startOO
classBlockdecl.(TDZ)XX
importModulesame as exportXX
varFunctionstart, partiallyOO
  • decl. (TDZ): 선언된 범위(Scope) 내에서 실행될 때 접근 가능하다.
  • Duplicates: 중복 선언이 가능한가에 대한 여부
  • Global prop.: 전역 객체에 추가되는지에 대한 여부
  • 함수의 Scope는 일반적으로 Block 범위, strict mode가 아닐 때는 Function 범위

아래에서 더 자세하게 살펴보자

Temporal Dead Zone(TDZ)

  • let, const에 해당한다.
{
  console.log(x); // ???
  const x;
}

선언된 범위(Scope) 내에서 선언까지 도달하기 전 사용이 불가능하기 떄문에 에러를 뱉는다.

범위 내에서 선언에 도달하기 까지의 구간을 TDZ(일시적 사용 불가 구간)라고 한다.

  • TDZ에서 변수는 초기화되어있지 않다.
  • 초기화되어있지 않은 변수 접근을 시도하면 ReferenceError가 발생한다.
  • 선언하는 부분에 도달하면 변수는 대입한 값으로 초기화 되거나 undefined가 된다.

다음 예제는 TDZ가 실제로 일시적으로 존재함을 알려준다.

if (true) {
  // myVar이 선언되어있는 스코프에 진입
  const func = () => {
    console.log(myVar) // 함수 실행시점에 myVar이 TDZ를 벗어났으면 실행
  }

  // 아래 myVar 선언되기 전에 사용하려는 경우 ReferenceError가 뜰 것이다.

  let myVar = 3 // TDZ가 끝났다.
  func() // myVar의 TDZ가 끝났기 때문에 에러가 아니다.
}

Function declaration

함수가 있는 Scope에 접근할 때 함수 선언은 Scope내 어디에 있든 항상 실행된다. 즉, Scope내 어디서든 선언만 되어있다면 언제든 사용할 수 있다.

하지만, 다음의 경우는 유의해야한다.

  • 단, const, let을 이용하여 함수를 선언/할당한 경우
  • 함수를 실행한 뒤에 선언한 변수가 함수 선언 내부에 쓰이는 경우
funcDecl() // funcDecl이 선언된 Scope니까 함수의 실행은 가능하다
// 그러나 함수의 내용을 보면 MY_STR const를 사용하는데, MY_STR는 아직 선언되지 않았으므로 에러가 발생한다.

const MY_STR = "abc"
function funcDecl() {
  assert.throws(
    () => MY_STR, // 함수 선언될 때 없음
    ReferenceError
  )
}

Class declaration

Class는 선언한 이후에 사용 가능해야한다. class의 상속 기능인 extends가 expression이기 때문이다. extends시에는 계산이 이뤄지기 때문에 다음과 같은 코드가 가능하다.

const c = new Cat() // 이럼 안된다.

const identity = x => x
class Cat extends identity(Animal) {}

다시말하자면, class의 선언은 extends를 통해 어떤 값을 받아 처리하는 expression이고, 때문에 expression에 대한 statement의 처리는 실행하는 시점에 이뤄진다.

ℹ️ expression은 값을 나타내고, statement는 행위의 선언이다.

var과 hoisting

👀 [[JavaScript - Hoisting]]

아까 표에서 var는 Javascript실행시 부분적으로 사용가능하다고 되어있었다.

var x = 123

var의 선언은 두 부분으로 나뉜다.

  • 선언부 var x: var로 선언된 변수를 담고있는 가장 안쪽의 함수 Scope
    • ⚠️ Block scope가 아님
  • 대입부 x = 123: 값은 대입한 시점 이후부터 사용가능
function f() {
  assert.equal(x, undefined) // 가장 안쪽의 함수 Scope에서 선언. undefined로 초기화됨
  if (true) {
    var x = 123 // 이제 123 값을 갖게됨 + Block안에서 선언했지만 위 설명대로..

    assert.equal(x, 123)
  }

  assert.equal(x, 123) // 여기선 123
}
JavaScript - Scope